/*
 * @(#)Stock.java	1.15 02/08/09 @(#)
 *
 * Copyright (c) 1999-2001 Sun Microsystems, Inc.  All rights reserved.
 * PROPRIETARY/CONFIDENTIAL
 * Use is subject to license terms.
 */

package example.stock;

/**
 * <p>This is a utility class that is used to parse data obtained from either
 * the quote server or the database and break it into fields for easy use
 * rather than spreading the parsing code around to a thousand different places
 * through out the program.</p>
 */
public final class Stock {

    /**
     * Name of the Stock
     */
    private static String name;

    /**
     * Time of the last trade
     */
    private static String time;

    /**
     * Price of the Stock
     */
    private static int price;

    /**
     * $ change
     */
    private static int change;

    /**
     * 52-week high
     */
    private static int high;

    /**
     * 52-week low
     */
    private static int low;

    /**
     * opening price on the day
     */
    private static int open;

    /**
     * previous high
     */
    private static int prev;

    /**
     * <p>Takes a <code>String</code> from the quote server or database and
     * parses the string into each field.  We first have to split it into
     * small strings and then parse each string that should be a number.
     *
     * @param quoteString the <code>String</code> to parse into the fields
     * @throws <code>NumberFormatException</code> is thrown if
     *            data that is not of the correct format is passed in -- where
     *            the number parts of the string cannot be converted to <code>
     *            Integers</code> because there are non-numeric characters
     *            in positions where numbers are expected
     * @throws <code>StringIndexOutOfBoundsException</code> is
     *            thrown if data that is not of the correct format is passed
     *            in -- where the deliminaters between the fields are not in
     *            the right spots, or the data is not of the correct length
     */
    public static void parse(String quoteString)
	throws NumberFormatException, StringIndexOutOfBoundsException {

        // get our starting index
        int index = quoteString.indexOf('"');
	if (index == -1) {
	    name = quoteString;
	    return;
	}

        // split the string up into it's fields
        name    = quoteString.substring(++index, 
			    	(index = quoteString.indexOf('"', index)));
        index += 3;
        time    = quoteString.substring(index, 
				(index = quoteString.indexOf('-', index))-1);
        index += 5;
        String Sprice  = quoteString.substring(index,
				(index = quoteString.indexOf('<', index)));
        index += 6;
        String Schange = quoteString.substring(index,
			       (index = quoteString.indexOf(',', index)));
        index += 2;
        String Slow    = quoteString.substring(index,
				(index = quoteString.indexOf(' ', index)));
        index += 3;
        String Shigh   = quoteString.substring(index,
				(index = quoteString.indexOf('"', index)));
        index += 2;
        String Sopen   = quoteString.substring(index,
				(index = quoteString.indexOf(',', index)));
        ++index;
        String Sprev   = quoteString.substring(index, quoteString.length()-2);

        // convert the strings that should be numbers into ints
        price = makeInt(Sprice);
        // remove the '+' sign if it exists
        Schange = (Schange.indexOf('+') == -1) ? 
	    Schange : Schange.substring(1, Schange.length());
        change = makeInt(Schange);
        prev   = makeInt(Sprev);
	if ("N/A".equals(Slow)) {
	    low = prev;
	} else {
	    low = makeInt(Slow);
	}
	if ("N/A".equals(Shigh)) {
	    high = prev;
	} else {
	    high = makeInt(Shigh);
	}
	if ("N/A".equals(Sopen)) {
	    open = prev; 
	} else {
	    open = makeInt(Sopen);
	}
    }

    /**
     * <p>Take a <code>String</code> representation of an int and the number of
     * decimal places that the <code>String</code> carries and make an <code>
     * int</code> out of it</p>
     * <p>Since there is no floating point support in MIDP/CLDC, we have to
     * convert the decimal numbers into <code>Integer</code>s. 
     * We do this by:</p>
     * <li> Looking at only the first 7 significant characters which, because
     *      of the decimal, means the first 6 numbers from left to right.</li>
     * <li> Looking at a maximum of 4 decimal places</li>
     * <li> We remove the decimal character (if there is one) and concatenate
     *      the numbers before and after the decimal so that we can convert
     *      to an integer and manipulate the value as a number</li>
     * <li> After doing this for each number, we have
     * <code>int</code> values but no
     *      notion of where the decimal place was.  To
     * alleviate this, we make
     * sure that each number has EXACTLY 4 decimal place holders. Therefore,
     * we can divide by 10000 to put the decimal place back in the same
     * spot.<BR>
     *<pre>
     *      Example: 100    -> 1000000 ->            /10000 = 100
     *      Example: 345.67 -> 34567   -> 3456700 -> /10000 = 345.67
     *      Example: 3.4526 -> 34526   ->            /10000 = 3.4526
     *</pre></li>
     *
     * @return the int value of the string
     * @param length
     * @param source the <code>String</code> value to convert
     * to an <code>int</code>
     */
    public static int makeInt(String source)
	throws NumberFormatException, StringIndexOutOfBoundsException {

        // cut the entire string down to 6 characters
        if (source.length() > 7) {
            source = source.substring(0, 6);
        }

        // cut the string down to 4 decimal places
        while (source.length() - (source.indexOf('.') + 1) > 4) {
            source = source.substring(0, source.length()-1);
        }

        // convert to an int
        int value  = (source.indexOf('.') == -1) ?
	    Integer.valueOf(source).intValue()
	    : Integer.valueOf(new String(
	    source.substring(0, source.indexOf('.')) +
	    source.substring(source.indexOf('.')+1,
	    source.length()))).intValue();

        // offset to 4 decimal placeholders
        int length = (source.indexOf('.') == -1) ? 0
                     : source.substring(source.indexOf('.')+1,
					source.length()).length();
        if (length < 4) {
            int diff = 4 - length;
            while (diff-- > 0) { value *= 10; }
        }
        return value;
    }

    /**
     * <p>Return the name of the stock</p>
     *
     * @return name (ticker symbol) of the stock
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static String getName(String quoteString) {
        parse(quoteString);
        return name;
    }

    /**
     * <p>Return the time of the last trade</p>
     *
     * @return time of the last trade of the stock
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static String getTime(String quoteString) {
        parse(quoteString);
        return time;
    }

    /**
     * <p>Return the price of the last trade of the stock</p>
     *
     * @return price of the last trade of the stock
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static int getPrice(String quoteString) {
        parse(quoteString);
        return price;
    }

    /**
     * <p>Return the $ change in the stock</p>
     *
     * @return $ change in the stock today
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static int getChange(String quoteString) {
        parse(quoteString);
        return change;
    }

    /**
     * <p>Return the 52-week high for the stock</p>
     *
     * @return 52-week high of the stock
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static int getHigh(String quoteString) {
        parse(quoteString);
        return high;
    }

    /**
     * <p>Return the 52-week low of the stock</p>
     *
     * @return 52-week low of the stock
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static int getLow(String quoteString) {
        parse(quoteString);
        return low;
    }

    /**
     * <p>Return the opening price of the stock</p>
     *
     * @return opening price of the stock today
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static int getOpen(String quoteString) {
        parse(quoteString);
        return open;
    }

    /**
     * <p>Return the previous high for the stock</p>
     *
     * @return previous high for the stock
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static int getPrevious(String quoteString) {
        parse(quoteString);
        return prev;
    }

    /**
     * <p>Convert an <code>int</code> into a <code>String</code>
     * with the decimal placed back in</p>
     *
     * @return The <code>String</code> value of the int
     * @param intNum the <code>int</code> value to convert
     * to a <code>String</code>
     */
    public static String convert(int intNum) {
        String s = String.valueOf(intNum);
        String pre = s.substring(0, ((s.length() < 4) ?
				     s.length() : s.length()-4));
        String suf = s.substring(((s.length() == pre.length()) ?
				  0 : s.length()-4), s.length());
        if (Integer.valueOf(suf).intValue() == 0) {
            return pre;
        }
        while (Integer.valueOf(suf.substring(suf.length()-1,
					     suf.length())).intValue() == 0) {
            suf = suf.substring(0, suf.length()-1);
        }
        return (pre + "." + suf);
    }
    /**
     * <p>String representation of price with decimal placed
     * back in the correct spot</p>
     *
     * @return current stock price
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static String getStringPrice(String quoteString) {
        parse(quoteString);
        return convert(price);
    }

    /**
     * <p>String representation of change with decimal placed
     * back in the correct spot</p>
     *
     * @return change in stock price today
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static String getStringChange(String quoteString) {
        parse(quoteString);
        return convert(change);
    }

    /**
     * <p>String representation of the 52-week high with decimal
     * placed back in the correct spot</p>
     *
     * @return 52-week high
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static String getStringHigh(String quoteString) {
        parse(quoteString);
        return convert(high);
    }

    /**
     * <p>String representation of the 52-week low with decimal
     * placed back in the correct spot</p>
     *
     * @return 52-week low
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static String getStringLow(String quoteString) {
        parse(quoteString);
        return convert(low);
    }

    /**
     * <p>String representation of the opening price with
     * decimal placed back in the correct spot</p>
     *
     * @return opening stock price
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static String getStringOpen(String quoteString) {
        parse(quoteString);
        return convert(open);
    }

    /**
     * <p>String representation of previous with decimal
     * placed back in the correct spot</p>
     *
     * @return previous high for the stock
     * @param  quoteString <code>String</code> to parse for the field data
     */
    public static String getStringPrevious(String quoteString) {
        parse(quoteString);
        return convert(prev);
    }
}
